home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1998 June / SGI Freeware 1998 June.iso / dist / fw_viewfax.idb / usr / freeware / src / viewfax-2.3 / faxexpand.c.z / faxexpand.c
C/C++ Source or Header  |  1997-09-09  |  20KB  |  728 lines

  1. /* Expand one page of fax data
  2.    Copyright (C) 1990, 1995  Frank D. Cringle.
  3.  
  4. This file is part of viewfax - g3/g4 fax processing software.
  5.      
  6. viewfax is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by the
  8. Free Software Foundation; either version 2 of the License, or (at your
  9. option) any later version.
  10.      
  11. This program is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14. General Public License for more details.
  15.      
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  19.  
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <sys/types.h>
  23. #include "faxexpand.h"
  24.  
  25. /* Note that NeedBits() only works for n <= 16 */
  26. #define NeedBits(n) do {                        \
  27.     if (BitsAvail < (n)) {                        \
  28.     BitAcc |= *sp++ << BitsAvail;                    \
  29.     BitsAvail += 16;                        \
  30.     }                                    \
  31. } while (0)
  32. #define GetBits(n)    (BitAcc & ((1<<(n))-1))
  33. #define ClrBits(n) do {                            \
  34.     BitsAvail -= (n);                            \
  35.     BitAcc >>= (n);                            \
  36. } while (0)
  37.  
  38. #ifdef DEBUG
  39. #define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0')
  40. #define LOOKUP(wid,tab)    do {                        \
  41.     int t;                                \
  42.     NeedBits(wid);                            \
  43.     TabEnt = tab + GetBits(wid);                    \
  44.     printf("%08lX/%d: %s%5d\t", BitAcc, BitsAvail,            \
  45.        StateNames[TabEnt->State], TabEnt->Param);            \
  46.     for (t = 0; t < TabEnt->Width; t++)                    \
  47.     DEBUG_SHOW;                            \
  48.     putchar('\n');                            \
  49.     fflush(stdout);                            \
  50.     ClrBits(TabEnt->Width);                        \
  51. } while (0)
  52.  
  53. #define SETVAL(x) do {                            \
  54.     *pa++ = RunLength + (x);                        \
  55.     printf("SETVAL: %d\t%d\n", RunLength + (x), a0);            \
  56.     a0 += x;                                \
  57.     RunLength = 0;                            \
  58. } while (0)
  59.  
  60. char *StateNames[] = {
  61.     "Null   ",
  62.     "Pass   ",
  63.     "Horiz  ",
  64.     "V0     ",
  65.     "VR     ",
  66.     "VL     ",
  67.     "Ext    ",
  68.     "TermW  ",
  69.     "TermB  ",
  70.     "MakeUpW",
  71.     "MakeUpB",
  72.     "MakeUp ",
  73.     "EOL    ",
  74. };
  75.  
  76. #else
  77. #define LOOKUP(wid,tab)    do {                        \
  78.     NeedBits(wid);                            \
  79.     TabEnt = tab + GetBits(wid);                    \
  80.     ClrBits(TabEnt->Width);                        \
  81. } while (0)
  82.  
  83. #define SETVAL(x) do {                            \
  84.     *pa++ = RunLength + (x);                        \
  85.     a0 += x;                                \
  86.     RunLength = 0;                            \
  87. } while (0)
  88. #endif
  89.  
  90. #define dumpruns(runs) do {                        \
  91.     printf("-------------------- %d\n", LineNum);            \
  92.     for (pa = runs, a0 = 0; a0 < lastx; a0 += *pa++)            \
  93.     printf("%4d %d\n", a0, *pa);                    \
  94. } while (0)
  95.  
  96. #define EndOfData(pn)    (sp >= pn->data + pn->length/sizeof(*pn->data))
  97.  
  98. /* This macro handles coding errors in G3 data.
  99.    We redefine it below for the G4 case */
  100. #define SKIP_EOL do {                            \
  101.     while (!EndOfData(pn)) {                        \
  102.     NeedBits(11);                            \
  103.     if (GetBits(11) == 0)                        \
  104.         break;                            \
  105.     ClrBits(11);                            \
  106.     }                                    \
  107.     ClrBits(11);                            \
  108.     goto EOL;                                \
  109. } while (0)
  110. #define eol2lab    EOL2:
  111.  
  112. /* the line expanders are written as macros so that they can be reused
  113.    (twice each) but still have direct access to the local variables of
  114.    the "calling" function */
  115. #define expand1d() do {                            \
  116.     while (a0 < lastx) {                        \
  117.     int done = 0;                            \
  118.     while (!done) {        /* white first */            \
  119.         LOOKUP(12, WhiteTable);                    \
  120.         switch (TabEnt->State) {                    \
  121.         case S_EOL:                            \
  122.         EOLcnt = 1;                        \
  123.         goto EOL;                        \
  124.         case S_TermW:                        \
  125.         SETVAL(TabEnt->Param);                    \
  126.         done = 1;                        \
  127.         break;                            \
  128.         case S_MakeUpW:                        \
  129.         case S_MakeUp:                        \
  130.         a0 += TabEnt->Param;                    \
  131.         RunLength += TabEnt->Param;                \
  132.         break;                            \
  133.         case S_Ext:                            \
  134.         unexpected("Extension code", LineNum);            \
  135.         SKIP_EOL;                        \
  136.         break;                            \
  137.         default:                            \
  138.         unexpected("WhiteTable", LineNum);            \
  139.         SKIP_EOL;                        \
  140.         break;                            \
  141.         }                                \
  142.     }                                \
  143.     done = 0;                            \
  144.     while (!done) {        /* then black */            \
  145.         LOOKUP(13, BlackTable);                    \
  146.         switch (TabEnt->State) {                    \
  147.         case S_EOL:                            \
  148.         EOLcnt = 1;                        \
  149.         goto EOL;                        \
  150.         case S_TermB:                        \
  151.         SETVAL(TabEnt->Param);                    \
  152.         done = 1;                        \
  153.         break;                            \
  154.         case S_MakeUpB:                        \
  155.         case S_MakeUp:                        \
  156.         a0 += TabEnt->Param;                    \
  157.         RunLength += TabEnt->Param;                \
  158.         break;                            \
  159.         case S_Ext:                            \
  160.         unexpected("Extension code", LineNum);            \
  161.         SKIP_EOL;                        \
  162.         break;                            \
  163.         default:                            \
  164.         unexpected("BlackTable", LineNum);            \
  165.         SKIP_EOL;                        \
  166.         break;                            \
  167.         }                                \
  168.     }                                \
  169.     }                                    \
  170.  EOL: ;                                    \
  171. } while (0)
  172.  
  173. #define CHECK_b1 do {                            \
  174.     if (pa != thisrun) while (b1 <= a0 && b1 < lastx) {            \
  175.     b1 += pb[0] + pb[1];                        \
  176.     pb += 2;                            \
  177.     }                                    \
  178. } while (0)
  179.  
  180. #define expand2d(eolab) do {                        \
  181.     while (a0 < lastx) {                        \
  182.     LOOKUP(7, MainTable);                        \
  183.     switch (TabEnt->State) {                    \
  184.     case S_Pass:                            \
  185.         CHECK_b1;                            \
  186.         b1 += *pb++;                        \
  187.         RunLength += b1 - a0;                    \
  188.         a0 = b1;                            \
  189.         b1 += *pb++;                        \
  190.         break;                            \
  191.     case S_Horiz:                            \
  192.         if ((pa-run0)&1) {                        \
  193.         int done = 0;                        \
  194.         while (!done) { /* black first */            \
  195.             LOOKUP(13, BlackTable);                \
  196.             switch (TabEnt->State) {                \
  197.             case S_TermB:                    \
  198.             SETVAL(TabEnt->Param);                \
  199.             done = 1;                    \
  200.             break;                        \
  201.             case S_MakeUpB:                    \
  202.             case S_MakeUp:                    \
  203.             a0 += TabEnt->Param;                \
  204.             RunLength += TabEnt->Param;            \
  205.             break;                        \
  206.             default:                        \
  207.             unexpected("BlackTable", LineNum);        \
  208.             SKIP_EOL;                    \
  209.             break;                        \
  210.             }                            \
  211.         }                            \
  212.         done = 0;                        \
  213.         while (!done) { /* then white */            \
  214.             LOOKUP(12, WhiteTable);                \
  215.             switch (TabEnt->State) {                \
  216.             case S_TermW:                    \
  217.             SETVAL(TabEnt->Param);                \
  218.             done = 1;                    \
  219.             break;                        \
  220.             case S_MakeUpW:                    \
  221.             case S_MakeUp:                    \
  222.             a0 += TabEnt->Param;                \
  223.             RunLength += TabEnt->Param;            \
  224.             break;                        \
  225.             default:                        \
  226.             unexpected("WhiteTable", LineNum);        \
  227.             SKIP_EOL;                    \
  228.             break;                        \
  229.             }                            \
  230.         }                            \
  231.         }                                \
  232.         else {                            \
  233.         int done = 0;                        \
  234.         while (!done) { /* white first */            \
  235.             LOOKUP(12, WhiteTable);                \
  236.             switch (TabEnt->State) {                \
  237.             case S_TermW:                    \
  238.             SETVAL(TabEnt->Param);                \
  239.             done = 1;                    \
  240.             break;                        \
  241.             case S_MakeUpW:                    \
  242.             case S_MakeUp:                    \
  243.             a0 += TabEnt->Param;                \
  244.             RunLength += TabEnt->Param;            \
  245.             break;                        \
  246.             default:                        \
  247.             unexpected("WhiteTable", LineNum);        \
  248.             SKIP_EOL;                    \
  249.             break;                        \
  250.             }                            \
  251.         }                            \
  252.         done = 0;                        \
  253.         while (!done) { /* then black */            \
  254.             LOOKUP(13, BlackTable);                \
  255.             switch (TabEnt->State) {                \
  256.             case S_TermB:                    \
  257.             SETVAL(TabEnt->Param);                \
  258.             done = 1;                    \
  259.             break;                        \
  260.             case S_MakeUpB:                    \
  261.             case S_MakeUp:                    \
  262.             a0 += TabEnt->Param;                \
  263.             RunLength += TabEnt->Param;            \
  264.             break;                        \
  265.             default:                        \
  266.             unexpected("BlackTable", LineNum);        \
  267.             SKIP_EOL;                    \
  268.             break;                        \
  269.             }                            \
  270.         }                            \
  271.         }                                \
  272.         CHECK_b1;                            \
  273.         break;                            \
  274.     case S_V0:                            \
  275.         CHECK_b1;                            \
  276.         SETVAL(b1 - a0);                        \
  277.         b1 += *pb++;                        \
  278.         break;                            \
  279.     case S_VR:                            \
  280.         CHECK_b1;                            \
  281.         SETVAL(b1 - a0 + TabEnt->Param);                \
  282.         b1 += *pb++;                        \
  283.         break;                            \
  284.     case S_VL:                            \
  285.         CHECK_b1;                            \
  286.         SETVAL(b1 - a0 - TabEnt->Param);                \
  287.         b1 -= *--pb;                        \
  288.         break;                            \
  289.     case S_Ext:                            \
  290.         *pa++ = lastx - a0;                        \
  291.         if (verbose)                        \
  292.         fprintf(stderr, "Line %d: extension code\n", LineNum);    \
  293.         SKIP_EOL;                            \
  294.         break;                            \
  295.     case S_EOL:                            \
  296.         *pa++ = lastx - a0;                        \
  297.         NeedBits(4);                        \
  298.         if (GetBits(4) && verbose) /* already seen 7 zeros */    \
  299.         fprintf(stderr, "Line %d: Bad EOL\n", LineNum);        \
  300.         ClrBits(4);                            \
  301.         EOLcnt = 1;                            \
  302.         goto eolab;                            \
  303.         break;                            \
  304.     default:                            \
  305.         unexpected("MainTable", LineNum);                \
  306.         SKIP_EOL;                            \
  307.         break;                            \
  308.     }                                \
  309.     }                                    \
  310.     if (RunLength) {                            \
  311.     /* expect a final V0 */                        \
  312.     NeedBits(1);                            \
  313.     if (!GetBits(1)) {                        \
  314.         unexpected("MainTable", LineNum);                \
  315.         SKIP_EOL;                            \
  316.     }                                \
  317.     ClrBits(1);                            \
  318.     SETVAL(0);                            \
  319.     }                                    \
  320.  eol2lab ;                                \
  321. } while (0)
  322.  
  323. static void
  324. unexpected(char *what, int LineNum)
  325. {
  326.     if (verbose)
  327.     fprintf(stderr, "Line %d: Unexpected state in %s\n",
  328.         LineNum, what);
  329. }
  330.  
  331. /* Expand tiff modified huffman data (g3-1d without EOLs) */
  332. void
  333. MHexpand(struct pagenode *pn, drawfunc df)
  334. {
  335.     int a0;            /* reference element */
  336.     int lastx = pn->width;    /* copy line width to register */
  337.     t32bits BitAcc;        /* bit accumulator */
  338.     int BitsAvail;        /* # valid bits in BitAcc */
  339.     int RunLength;        /* Length of current run */
  340.     t16bits *sp;        /* pointer into compressed data */
  341.     pixnum *pa;            /* pointer into new line */
  342.     int EOLcnt;            /* number of consecutive EOLs */
  343.     int    LineNum;        /* line number */
  344.     pixnum *runs;        /* list of run lengths */
  345.     struct tabent *TabEnt;
  346.  
  347.     sp = pn->data;
  348.     BitAcc = 0;
  349.     BitsAvail = 0;
  350.     lastx = pn->width;
  351.     runs = (pixnum *) xmalloc(lastx * sizeof(pixnum));
  352.     for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
  353. #ifdef DEBUG
  354.     printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
  355.     printf("-------------------- %d\n", LineNum);
  356.     fflush(stdout);
  357. #endif
  358.     RunLength = 0;
  359.     pa = runs;
  360.     a0 = 0;
  361.     EOLcnt = 0;
  362.     if (BitsAvail & ~8)    /* skip to byte boundary */
  363.         ClrBits(BitsAvail & ~8);
  364.     expand1d();
  365.     if (RunLength)
  366.         SETVAL(0);
  367.     if (a0 != lastx) {
  368.         if (verbose)
  369.         fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx);
  370.         while (a0 > lastx)
  371.         a0 -= *--pa;
  372.         if (a0 < lastx) {
  373.         if ((pa - runs) & 1)
  374.             SETVAL(0);
  375.         SETVAL(lastx - a0);
  376.         }
  377.     }
  378.     (*df)(runs, LineNum++, pn);
  379.     }
  380.     free(runs);
  381. }
  382.  
  383. /* Expand group-3 1-dimensional data */
  384. void
  385. g31expand(struct pagenode *pn, drawfunc df)
  386. {
  387.     int a0;            /* reference element */
  388.     int lastx = pn->width;    /* copy line width to register */
  389.     t32bits BitAcc;        /* bit accumulator */
  390.     int BitsAvail;        /* # valid bits in BitAcc */
  391.     int RunLength;        /* Length of current run */
  392.     t16bits *sp;        /* pointer into compressed data */
  393.     pixnum *pa;            /* pointer into new line */
  394.     int EOLcnt;            /* number of consecutive EOLs */
  395.     int    LineNum;        /* line number */
  396.     pixnum *runs;        /* list of run lengths */
  397.     struct tabent *TabEnt;
  398.  
  399.     sp = pn->data;
  400.     BitAcc = 0;
  401.     BitsAvail = 0;
  402.     lastx = pn->width;
  403.     runs = (pixnum *) xmalloc(lastx * sizeof(pixnum));
  404.     EOLcnt = 0;
  405.     for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
  406. #ifdef DEBUG
  407.     printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
  408.     printf("-------------------- %d\n", LineNum);
  409.     fflush(stdout);
  410. #endif
  411.     if (EOLcnt == 0)
  412.         while (!EndOfData(pn)) {
  413.         /* skip over garbage after a coding error */
  414.         NeedBits(11);
  415.         if (GetBits(11) == 0)
  416.             break;
  417.         ClrBits(1);
  418.         }
  419.     for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) {
  420.         /* we have seen 11 zeros, which implies EOL,
  421.            skip possible fill bits too */
  422.         while (1) {
  423.         NeedBits(8);
  424.         if (GetBits(8))
  425.             break;
  426.         ClrBits(8);
  427.         }
  428.         while (GetBits(1) == 0)
  429.         ClrBits(1);
  430.         ClrBits(1);        /* the eol flag */
  431.         NeedBits(11);
  432.         if (GetBits(11))
  433.         break;
  434.         ClrBits(11);
  435.     }
  436.     if (EOLcnt > 1 && EOLcnt != 6 && verbose)
  437.         fprintf(stderr, "Line %d: bad RTC (%d EOLs)\n", LineNum, EOLcnt);
  438.     if (EOLcnt >= 6 || EndOfData(pn)) {
  439.         free(runs);
  440.         return;
  441.     }
  442.     RunLength = 0;
  443.     pa = runs;
  444.     a0 = 0;
  445.     EOLcnt = 0;
  446.     expand1d();
  447.     if (RunLength)
  448.         SETVAL(0);
  449.     if (a0 != lastx) {
  450.         if (verbose)
  451.         fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx);
  452.         while (a0 > lastx)
  453.         a0 -= *--pa;
  454.         if (a0 < lastx) {
  455.         if ((pa - runs) & 1)
  456.             SETVAL(0);
  457.         SETVAL(lastx - a0);
  458.         }
  459.     }
  460.     (*df)(runs, LineNum++, pn);
  461.     }
  462.     free(runs);
  463. }
  464.  
  465. /* Expand group-3 2-dimensional data */
  466. void
  467. g32expand(struct pagenode *pn, drawfunc df)
  468. {
  469.     int RunLength;        /* Length of current run */
  470.     int a0;            /* reference element */
  471.     int b1;            /* next change on previous line */
  472.     int lastx = pn->width;    /* copy line width to register */
  473.     pixnum *run0, *run1;    /* run length arrays */
  474.     pixnum *thisrun, *pa, *pb;    /* pointers into runs */
  475.     t16bits *sp;        /* pointer into compressed data */
  476.     t32bits BitAcc;        /* bit accumulator */
  477.     int BitsAvail;        /* # valid bits in BitAcc */
  478.     int EOLcnt;            /* number of consecutive EOLs */
  479.     int    refline = 0;        /* 1D encoded reference line */
  480.     int    LineNum;        /* line number */
  481.     struct tabent *TabEnt;
  482.  
  483.     sp = pn->data;
  484.     BitAcc = 0;
  485.     BitsAvail = 0;
  486.     /* allocate space for 2 runlength arrays */
  487.     run0 = (pixnum *) xmalloc(2 * ((lastx+5)&~1) * sizeof(pixnum));
  488.     run1 = run0 + ((lastx+5)&~1);
  489.     run1[0] = lastx;
  490.     run1[1] = 0;
  491.     EOLcnt = 0;
  492.     for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
  493. #ifdef DEBUG
  494.     printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
  495.     printf("-------------------- %d\n", LineNum);
  496.     fflush(stdout);
  497. #endif
  498.     if (EOLcnt == 0)
  499.         while (!EndOfData(pn)) {
  500.         /* skip over garbage after a coding error */
  501.         NeedBits(11);
  502.         if (GetBits(11) == 0)
  503.             break;
  504.         ClrBits(1);
  505.         }
  506.     for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) {
  507.         /* we have seen 11 zeros, which implies EOL,
  508.            skip possible fill bits too */
  509.         while (1) {
  510.         NeedBits(8);
  511.         if (GetBits(8))
  512.             break;
  513.         ClrBits(8);
  514.         }
  515.         while (GetBits(1) == 0)
  516.         ClrBits(1);
  517.         ClrBits(1);        /* the eol flag */
  518.         NeedBits(12);
  519.         refline = GetBits(1); /* 1D / 2D flag */
  520.         ClrBits(1);
  521.         if (GetBits(11))
  522.         break;
  523.         ClrBits(11);
  524.     }
  525.     if (EOLcnt > 1 && EOLcnt != 6 && verbose)
  526.         fprintf(stderr, "Line %d: bad RTC (%d EOLs)\n", LineNum, EOLcnt);
  527.     if (EOLcnt >= 6 || EndOfData(pn)) {
  528.         free(run0);
  529.         return;
  530.     }
  531.     if (LineNum == 0 && refline == 0 && verbose)
  532.         fprintf(stderr, "First line is 2-D encoded\n");
  533.     RunLength = 0;
  534.     if (LineNum & 1) {
  535.         pa = run1;
  536.         pb = run0;
  537.     }
  538.     else {
  539.         pa = run0;
  540.         pb = run1;
  541.     }
  542.     thisrun = pa;
  543.     EOLcnt = 0;
  544.     a0 = 0;
  545.     b1 = *pb++;
  546.  
  547.     if (refline) {
  548.         expand1d();
  549.     }
  550.     else {
  551.         expand2d(EOL2);
  552.     }
  553.     if (RunLength)
  554.         SETVAL(0);
  555.     if (a0 != lastx) {
  556.         if (verbose)
  557.         fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx);
  558.         while (a0 > lastx)
  559.         a0 -= *--pa;
  560.         if (a0 < lastx) {
  561.         if ((pa - run0) & 1)
  562.             SETVAL(0);
  563.         SETVAL(lastx - a0);
  564.         }
  565.     }
  566.     SETVAL(0);    /* imaginary change at end of line for reference */
  567.     (*df)(thisrun, LineNum++, pn);
  568.     }
  569.     free(run0);
  570. }
  571.  
  572. /* Redefine the "skip to eol" macro.  We cannot recover from coding
  573.    errors in G4 data */
  574. #undef SKIP_EOL
  575. #undef eol2lab
  576. #define SKIP_EOL do {                            \
  577.     if (verbose)                            \
  578.     fprintf(stderr, "Line %d: G4 coding error\n", LineNum);        \
  579.     free(run0);                                \
  580.     return;                                \
  581. } while (0)
  582. #define eol2lab
  583.  
  584. /* Expand group-4 data */
  585. void
  586. g4expand(struct pagenode *pn, drawfunc df)
  587. {
  588.     int RunLength;        /* Length of current run */
  589.     int a0;            /* reference element */
  590.     int b1;            /* next change on previous line */
  591.     int lastx = pn->width;    /* copy line width to register */
  592.     pixnum *run0, *run1;    /* run length arrays */
  593.     pixnum *thisrun, *pa, *pb;    /* pointers into runs */
  594.     t16bits *sp;        /* pointer into compressed data */
  595.     t32bits BitAcc;        /* bit accumulator */
  596.     int BitsAvail;        /* # valid bits in BitAcc */
  597.     int    LineNum;        /* line number */
  598.     int EOLcnt;
  599.     struct tabent *TabEnt;
  600.  
  601.     sp = pn->data;
  602.     BitAcc = 0;
  603.     BitsAvail = 0;
  604.     /* allocate space for 2 runlength arrays */
  605.     run0 = (pixnum *) xmalloc(2 * ((lastx+5)&~1) * sizeof(pixnum));
  606.     run1 = run0 + ((lastx+5)&~1);
  607.     run1[0] = lastx;        /* initial reference line */
  608.     run1[1] = 0;
  609.  
  610.     for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
  611. #ifdef DEBUG
  612.     printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
  613.     printf("-------------------- %d\n", LineNum);
  614.     fflush(stdout);
  615. #endif
  616.     RunLength = 0;
  617.     if (LineNum & 1) {
  618.         pa = run1;
  619.         pb = run0;
  620.     }
  621.     else {
  622.         pa = run0;
  623.         pb = run1;
  624.     }
  625.     thisrun = pa;
  626.     a0 = 0;
  627.     b1 = *pb++;
  628.     expand2d(EOFB);
  629.     if (a0 < lastx) {
  630.         if ((pa - run0) & 1)
  631.         SETVAL(0);
  632.         SETVAL(lastx - a0);
  633.     }
  634.     SETVAL(0);    /* imaginary change at end of line for reference */
  635.     (*df)(thisrun, LineNum++, pn);
  636.     continue;
  637.     EOFB:
  638.     NeedBits(13);
  639.     if (GetBits(13) != 0x1001 && verbose)
  640.         fputs("Bad RTC\n", stderr);
  641.     break;
  642.     }
  643.     free(run0);
  644. }
  645.  
  646. static unsigned char zerotab[256] = {
  647.     0x88, 0x07, 0x16, 0x06, 0x25, 0x05, 0x15, 0x05,
  648.     0x34, 0x04, 0x14, 0x04, 0x24, 0x04, 0x14, 0x04,
  649.     0x43, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03,
  650.     0x33, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03,
  651.     0x52, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
  652.     0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
  653.     0x42, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
  654.     0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
  655.     0x61, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  656.     0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  657.     0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  658.     0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  659.     0x51, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  660.     0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  661.     0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  662.     0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  663.     0x70, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  664.     0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  665.     0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  666.     0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  667.     0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  668.     0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  669.     0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  670.     0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  671.     0x60, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  672.     0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  673.     0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  674.     0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  675.     0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  676.     0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  677.     0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  678.     0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00
  679. };
  680.  
  681. #define check(v) do {                            \
  682.     prezeros = zerotab[v];                        \
  683.     postzeros = prezeros & 15;                        \
  684.     prezeros >>= 4;                            \
  685.     if (prezeros == 8) {                        \
  686.     zeros += 8;                            \
  687.     continue;                            \
  688.     }                                    \
  689.     if (zeros + prezeros < 11) {                    \
  690.     empty = 0;                            \
  691.     zeros = postzeros;                        \
  692.     continue;                            \
  693.     }                                    \
  694.     zeros = postzeros;                            \
  695.     if (empty)                                \
  696.     EOLcnt++;                            \
  697.     lines++;                                \
  698.     empty = 1;                                \
  699. } while (0)
  700.  
  701. /* count fax lines */
  702. int
  703. G3count(struct pagenode *pn, int twoD)
  704. {
  705.     t16bits *p = pn->data;
  706.     t16bits *end = p + pn->length/sizeof(*p);
  707.     int lines = 0;        /* lines seen so far */
  708.     int zeros = 0;        /* number of consecutive zero bits seen */
  709.     int EOLcnt = 0;        /* number of consecutive EOLs seen */
  710.     int empty = 1;        /* empty line */
  711.     int prezeros, postzeros;
  712.  
  713.     while (p < end && EOLcnt < 6) {
  714.     t16bits bits = *p++;
  715.     check(bits&255);
  716.     if (twoD && (prezeros + postzeros == 7)) {
  717.         if (postzeros || ((bits & 0x100) == 0))
  718.         zeros--;
  719.     }
  720.     check(bits>>8);
  721.     if (twoD && (prezeros + postzeros == 7)) {
  722.         if (postzeros || ((p < end) && ((*p & 1) == 0)))
  723.         zeros--;
  724.     }
  725.     }
  726.     return lines - EOLcnt;    /* don't count trailing EOLs */
  727. }
  728.